//
// Created by jinyf on 2021/7/9.
//

#include <memory.h>
#include "VideoChannel.h"
#include "maniulog.h"

void VideoChannel::setVideoEncInfo(int width, int height, int fps, int bitrate) {

    mWidth = width;
    mHeight = height;
    mFps = fps;
    mBitrate = bitrate;

    ySize = width * height;
    uvSize = ySize / 4;

    LOGE("x264_encoder_close 1");
    if (videoCodec) {
        x264_encoder_close(videoCodec);
        videoCodec = 0;
    }
    LOGE("x264_encoder_close 2");

    //定义参数
    x264_param_t param;
    x264_param_default_preset(&param, "ultrafast", "zerolatency");

    //编码等级
    param.i_level_idc = 32;
    param.i_csp = X264_CSP_I420;

    param.i_width = width;
    param.i_height = height;

    //B帧,一般直播里面是没有B帧的,应为有会卡顿
    param.i_bframe = 0;
    param.rc.i_rc_method = X264_RC_ABR;

    //单位是K，所以除以1024
    param.rc.i_bitrate = bitrate / 1024;

    param.i_fps_num = fps;
    param.i_fps_den = 1;

    param.i_timebase_den = param.i_fps_num;
    param.i_timebase_num = param.i_fps_den;


    param.b_vfr_input = 0;
    //I帧间隔
    param.i_keyint_max = fps * 2;

    //让每个I帧带上sps pps
    param.b_repeat_headers = 1;

    //线程数
    param.i_threads = 1;

    //编码质量
    x264_param_apply_profile(&param, "baseline");

    videoCodec = x264_encoder_open(&param);

    pic_in = new x264_picture_t;

    //设置初始大小
    x264_picture_alloc(pic_in, X264_CSP_I420, width, height);

}

VideoChannel::VideoChannel() {

}

VideoChannel::~VideoChannel() {

}

void VideoChannel::encodeData(int8_t *data) {

    memcpy(pic_in->img.plane[0], data, ySize);
    for (int i = 0; i < uvSize; ++i) {
        //间隔1个字节取一个数据
        //u数据
        *(pic_in->img.plane[1] + i) = *(data + ySize + i * 2 + 1);
        //v数据
        *(pic_in->img.plane[2] + i) = *(data + ySize + i * 2);
    }


    //开始编码H264码流

    //编码出了几个 nalu （暂时理解为帧）  1   pi_nal  1  永远是1
    // 应为camera，所以目前只会有1帧
    //第一次是3，应为有sps和pps
    int pi_nal;
    x264_nal_t *pp_nals;
    x264_picture_t pic_out;

    LOGE("videoCodec value  %d", videoCodec);

    x264_encoder_encode(videoCodec, &pp_nals, &pi_nal, pic_in, &pic_out);
    LOGE("编码出的帧数  %d", pi_nal);


    uint8_t sps[100];
    uint8_t pps[100];
    int sps_len,pps_len;

    if (pi_nal > 0) {
        for (int i = 0; i < pi_nal; ++i) {
//            javaCallHelper->postH264(reinterpret_cast<char *>(pp_nals[i].p_payload), pp_nals[i].i_payload);
            if (pp_nals[i].i_type==NAL_SPS){
                sps_len=pp_nals[i].i_payload-4;
                memcpy(sps,pp_nals[i].p_payload+4,sps_len);
            }else if (pp_nals[i].i_type==NAL_PPS){
                LOGE("PPS 1");
                pps_len=pp_nals[i].i_payload-4;
                memcpy(pps,pp_nals[i].p_payload+4,pps_len);
                LOGE("PPS 2");
                sendSpsPps(sps, pps, sps_len, pps_len);
                LOGE("PPS 3");
            } else{
                LOGE("FRAME 1");
                //关键帧、非关键帧
                sendFrame(pp_nals[i].i_type,pp_nals[i].i_payload,pp_nals[i].p_payload);

                LOGE("FRAME 2");
            }


        }
    }

    return;

}




void VideoChannel::sendSpsPps(uint8_t *sps, uint8_t *pps, int sps_len, int pps_len) {
    RTMPPacket *packet = new RTMPPacket;
    int bodysize = 13 + sps_len + 3 + pps_len;
    RTMPPacket_Alloc(packet, bodysize);
    int i = 0;
    //固定头
    packet->m_body[i++] = 0x17;
    //类型
    packet->m_body[i++] = 0x00;
    //composition time 0x000000
    packet->m_body[i++] = 0x00;
    packet->m_body[i++] = 0x00;
    packet->m_body[i++] = 0x00;

    //版本
    packet->m_body[i++] = 0x01;
    //编码规格
    packet->m_body[i++] = sps[1];
    packet->m_body[i++] = sps[2];
    packet->m_body[i++] = sps[3];
    packet->m_body[i++] = 0xFF;

    //整个sps
    packet->m_body[i++] = 0xE1;
    //sps长度
    packet->m_body[i++] = (sps_len >> 8) & 0xff;
    packet->m_body[i++] = sps_len & 0xff;
    memcpy(&packet->m_body[i], sps, sps_len);
    i += sps_len;

    //pps
    packet->m_body[i++] = 0x01;
    packet->m_body[i++] = (pps_len >> 8) & 0xff;
    packet->m_body[i++] = (pps_len) & 0xff;
    memcpy(&packet->m_body[i], pps, pps_len);


    //视频
    packet->m_packetType = RTMP_PACKET_TYPE_VIDEO;
    packet->m_nBodySize = bodysize;
    //随意分配一个管道（尽量避开rtmp.c中使用的）
    packet->m_nChannel = 10;
    //sps pps没有时间戳
    packet->m_nTimeStamp = 0;
    //不使用绝对时间
    packet->m_hasAbsTimestamp = 0;
    packet->m_headerType = RTMP_PACKET_SIZE_MEDIUM;

    LOGE("cc 1");
    if (this->callback) {
        LOGE("cc 2");
        LOGE("this->callback %x",this->callback);
        LOGE("packet m_nBodySize %d",packet->m_nBodySize);
        this->callback(packet);
    }
    LOGE("cc 3");
}



void VideoChannel::sendFrame(int type, int payload, uint8_t *p_payload) {
    //去掉 00 00 00 01 / 00 00 01
    if (p_payload[2] == 0x00){
        payload -= 4;
        p_payload += 4;
    } else if(p_payload[2] == 0x01){
        payload -= 3;
        p_payload += 3;
    }
    RTMPPacket *packet = new RTMPPacket;
    int bodysize = 9 + payload;
    RTMPPacket_Alloc(packet, bodysize);
    RTMPPacket_Reset(packet);
//    int type = payload[0] & 0x1f;
    packet->m_body[0] = 0x27;
    //关键帧
    if (type == NAL_SLICE_IDR) {
        LOGE("关键帧");
        packet->m_body[0] = 0x17;
    }
    //类型
    packet->m_body[1] = 0x01;
    //时间戳
    packet->m_body[2] = 0x00;
    packet->m_body[3] = 0x00;
    packet->m_body[4] = 0x00;
    //数据长度 int 4个字节 相当于把int转成4个字节的byte数组
    packet->m_body[5] = (payload >> 24) & 0xff;
    packet->m_body[6] = (payload >> 16) & 0xff;
    packet->m_body[7] = (payload >> 8) & 0xff;
    packet->m_body[8] = (payload) & 0xff;

    //图片数据
    memcpy(&packet->m_body[9],p_payload,  payload);

    packet->m_hasAbsTimestamp = 0;
    packet->m_nBodySize = bodysize;
    packet->m_packetType = RTMP_PACKET_TYPE_VIDEO;
    packet->m_nChannel = 0x10;
    packet->m_headerType = RTMP_PACKET_SIZE_LARGE;
    callback(packet);
}

void VideoChannel::setVideoCallback(VideoChannel::VideoCallback cc) {
    LOGE("cc %x",cc);
    this->callback = cc;
}
